AngularのDatePipeでタイムゾーン付きの日時変換をする時の注意点
こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。
みなさま、AngularのPipeの一つ「DatePipe」は使われていますでしょうか?
コードベースでのよくある使い方は、UI上に表示したい日付フォーマットを以下のように変換するパターンかと思います。
this.datePipe.transform(new Date(), 'yyyy/MM/dd HH:mm:ss');
この際に、タイムゾーン付きの日付を変換する場合は、注意するべき点があることを初めて知ったので、本エントリにて説明したいと思います。
やりたかったこと
今回、やりたかったことは以下の通りです。
- サーバー側のAPIが、JSTのタイムゾーン付きの日付データを返却する
- 返却された日付をフロントエンド(Angular)で、JSTのまま画面に表示したい
想定外だった挙動
以下のようなコードでtargetDate
にJSTの日付データが入っている場合、formattedDate
にフォーマット変換後の値が入るのですが、この場合ローカル環境のタイムゾーンによって値が変わります。
formattedDate = this.datePipe.transform(targetDate), 'yyyy/MM/dd HH:mm:ss');
詳しく
サンプルとして、以下のようなコードで「2020/12/25 22:15:30+0900」(JSTの日付)が、画面上でどのように表示されるかを試してみました。
import { DatePipe } from '@angular/common'; import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-date-pipe-sample', templateUrl: './date-pipe-sample.component.html', styleUrls: ['./date-pipe-sample.component.scss'], providers:[DatePipe] }) export class DatePipeSampleComponent implements OnInit { localTimezoneOffset:number = -(new Date().getTimezoneOffset() / 60); originalDateTime:Date = new Date('2020/12/25 22:15:30+0900'); dateTimeValue:string|null = ''; dateTimeValueWithTz:string|null = ''; constructor(public datePipe: DatePipe) { } ngOnInit(): void { this.dateTimeValue = this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss'); this.dateTimeValueWithTz = this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss', '+0900'); } }
<div> <div>Local Timezone Offset:</div> <hr class="fade"> <div class="terminal"> <pre>{{localTimezoneOffset}} Hours</pre> </div> <br/> <div>DateTime:</div> <hr class="fade"> <div class="terminal"> <pre>{{dateTimeValue}}</pre> </div> <br/> <div>DateTime with Timezone:</div> <hr class="fade"> <div class="terminal"> <pre>{{dateTimeValueWithTz}}</pre> </div> </div>
ローカル環境のタイムゾーンが「(UTC+09:00)大阪、札幌、東京」の場合
まずは、ローカル環境(OS)のタイムゾーンが「(UTC+09:00)大阪、札幌、東京」の環境での結果です。
「Local Timezone Offset」は、タイムゾーンのオフセットとして認識されている時間です。タイムゾーンを「UTC+09:00」にしているので、9 Hours
となっています。
「DateTime」と「DateTime with Timezone」は、どちらもオリジナルのデータと同じく2020/12/25 22:15:30
ですので、この場合は特に問題ないかと思います。
ローカル環境のタイムゾーンが「(UTC+07:00)バンコク、ハノイ、ジャカルタ」の場合
つぎに、ローカル環境(OS)のタイムゾーンを「(UTC+07:00)バンコク、ハノイ、ジャカルタ」に変更して試してみます。
「Local Timezone Offset」は、タイムゾーンのオフセットとして認識されている時間です。タイムゾーンを「UTC+07:00」にしたので、7 Hours
になりました。
「DateTime」は、オリジナルのデータから時間が変わりました。 オリジナルのデータはJST(UTC+09:00)のデータだったので、そこから時差の2時間分の時間がズレて2020/12/25 20:15:30
となっています。
一方で、「DateTime with Timezone」は、オリジナルのデータと同じく2020/12/25 22:15:30
です。
これは、this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss', '+0900')
のように、第3引数のtimezone
にオフセットを明示的に指定したことにより、UI上も時間がズレていません。
具体的には以下に記載があります。
angular/date_pipe.ts at 11.0.2 · angular/angular · GitHub
- @param timezone A timezone offset (such as
'+0430'
), or a standard- UTC/GMT or continental US timezone abbreviation.
- When not supplied, uses the end-user's local system timezone.
記載のとおり、「指定なし」の場合はローカルシステムのタイムゾーンを参照するので、今回のケースでは+0700
を指定したのと同義となっています。
そのため、オリジナルのデータから2時間ズレた値が表示されたということになります。
このように、「JSTのまま時刻を表示したい」というケースでは注意が必要ですね。
まとめ
以上、AngularのDatePipeでタイムゾーン付きの日時変換をする時の注意点についてでした。
「サーバーサイドのAPIがUTCで時刻を返すケースで、フロントエンド側ではタイムゾーンに応じて表示を変えたい」というようなケースでは特に問題はありませんが、「サーバーサイドのAPIがJSTで時刻を返すケースで、フロントエンド側ではタイムゾーンに関わらずJSTで表示したい」というようなケースでは注意が必要ですね。
どなたかのお役に立てば幸いです。それでは!